package com.bsg.upm.service;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.check.CheckResult;
import com.bsg.upm.check.ClusterCheck;
import com.bsg.upm.constant.DictTypeConstants;
import com.bsg.upm.constant.OperateDictConstants;
import com.bsg.upm.constant.OperateDictTypeConstants;
import com.bsg.upm.constant.SysConstants;
import com.bsg.upm.dto.ClusterDto;
import com.bsg.upm.dto.NetworkingDto;
import com.bsg.upm.entity.AreaEntity;
import com.bsg.upm.entity.ClusterEntity;
import com.bsg.upm.entity.NetworkingEntity;
import com.bsg.upm.entity.SiteEntity;
import com.bsg.upm.entity.UserEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.http.RespJson;
import com.bsg.upm.http.RespJsonFactory;
import com.bsg.upm.util.DateUtils;
import com.bsg.upm.util.PrimaryKeyUtils;

/**
 * 集群管理业务处理类
 * 
 * @author HCK
 *
 */
@Service
public class ClusterService extends BaseService {

	@Resource
	private ClusterCheck clusterCheck;

	/**
	 * 集群查询
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson list(Map<String, Object> paramMap) throws APIException {
		try {
			// 结果集
			JSONArray results = new JSONArray();

			// 获取指定条件的集群
			List<ClusterEntity> clusters = clusterDao.list(paramMap);
			if (clusters.size() > 0) {
				String siteId = (String) paramMap.get("siteId");

				// 从MGM获取集群信息
				JSONArray mgmClusterInfos = listClusterInfoFromMGM(siteId);

				for (ClusterEntity cluster : clusters) {
					// 获取指定的集群信息(来源MGM)
					JSONObject mgmClusterInfo = findClusterInfoFromMGM(mgmClusterInfos, cluster.getRelateId());

					// 构建集群展示对象
					ClusterDto clusterDto = buildShowDto(cluster, false, mgmClusterInfo);
					results.add(clusterDto);
				}
			}

			return RespJsonFactory.buildOK(results);
		} catch (Exception e) {
			logger.error("集群查询异常", e);
			throw new APIException("集群查询异常:" + e.getMessage());
		}
	}

	/**
	 * 集群详情
	 * 
	 * @param clusterId
	 *            集群编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson get(String clusterId) throws APIException {
		try {
			// 获取指定的集群
			ClusterEntity cluster = clusterDao.get(clusterId);
			if (cluster == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该集群不存在");
			}

			// 站点
			String siteId = cluster.getArea().getSite().getId();

			// 从MGM获取指定的集群信息
			JSONObject mgmClusterInfo = getClusterInfoFromMGM(siteId, cluster.getRelateId());

			// 构建集群展示对象
			ClusterDto clusterDto = buildShowDto(cluster, true, mgmClusterInfo);

			return RespJsonFactory.buildOK(clusterDto);
		} catch (Exception e) {
			logger.error("集群获取异常", e);
			throw new APIException("集群获取异常:" + e.getMessage());
		}
	}

	/**
	 * 集群新增
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson save(Map<String, Object> paramMap) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_ADD;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 集群新增检查
			CheckResult chkRS = clusterCheck.checkSave(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 构建集群对象
			ClusterEntity cluster = buildCluster(paramMap);

			// 保存集群信息并保存集群使用的网段信息
			clusterDao.save(cluster);
			clusterDao.saveRelativeNetworking(cluster);

			String areaId = cluster.getArea().getId();
			String siteId = areaDao.get(areaId).getSite().getId();

			// 向MGM注册集群信息
			JSONObject respJson = saveClusterToMGM(siteId, paramMap);

			// 保存MGM集群编码
			cluster.setRelateId(respJson.getString("id"));
			clusterDao.updateRelateId(cluster);

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_CLUSTER, operateAcion, cluster.getId(), cluster.getName(),
					cluster.getCreateDateTime());

			return RespJsonFactory.buildCreated();
		} catch (Exception e) {
			logger.error("集群" + operateAcionText + "异常", e);
			throw new APIException("集群" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 集群编辑
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson update(Map<String, Object> paramMap) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_UPDATE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 集群编辑检查
			CheckResult chkRS = clusterCheck.checkUpdate(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 构建集群对象
			ClusterEntity cluster = buildClusterToUpdate(paramMap);

			// 更新集群信息并更新集群使用的网段信息
			clusterDao.update(cluster);
			clusterDao.removeRelativeNetworking(cluster.getId());
			clusterDao.saveRelativeNetworking(cluster);

			// 站点
			String siteId = cluster.getArea().getSite().getId();
			// 更新MGM上集群信息
			updateClusterFromMGM(siteId, cluster.getRelateId(), paramMap);

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_CLUSTER, operateAcion, cluster.getId(), cluster.getName());

			return RespJsonFactory.buildOK();
		} catch (Exception e) {
			logger.error("集群" + operateAcionText + "异常", e);
			throw new APIException("集群" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 集群启用/停用
	 * 
	 * @param id
	 *            集群编码
	 * @param enable
	 *            是否启用
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson enable(String id, boolean enable) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_DISABLE;
		if (enable) {
			operateAcion = OperateDictConstants.ACTION_ENABLE;
		}
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定的集群
			ClusterEntity cluster = clusterDao.get(id);

			// 集群启停检查
			CheckResult chkRS = null;
			if (enable) {
				chkRS = clusterCheck.checkEnable(cluster);
			} else {
				chkRS = clusterCheck.checkDisable(cluster);
			}
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 设置启停状态
			cluster.setEnabled(enable);
			clusterDao.updateEnabled(cluster);

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_CLUSTER, operateAcion, cluster.getId(), cluster.getName());

			return RespJsonFactory.buildOK();
		} catch (Exception e) {
			logger.error("集群" + operateAcionText + "异常", e);
			throw new APIException("集群" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 集群删除
	 * 
	 * @param id
	 *            集群编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson remove(String id) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_REMOVE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定的集群
			ClusterEntity cluster = clusterDao.get(id);

			// 集群删除检查
			CheckResult chkRS = clusterCheck.checkRemove(cluster);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 集群删除并删除和网段的关系
			clusterDao.remove(id);
			clusterDao.removeRelativeNetworking(id);

			// 站点
			String siteId = cluster.getArea().getSite().getId();
			// 从MGM上删除集群信息
			removeClusterFromMGM(siteId, cluster.getRelateId());

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_CLUSTER, operateAcion, cluster.getId(), cluster.getName());

			return RespJsonFactory.buildNoContent();
		} catch (Exception e) {
			logger.error("集群" + operateAcionText + "异常", e);
			throw new APIException("集群" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 从MGM获取集群信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @return MGM集群集合
	 * @throws APIException
	 *             API异常处理类
	 */
	private JSONArray listClusterInfoFromMGM(String siteId) throws APIException {
		String urlPattern = "/{0}/clusters";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION);
		RespJson httpRespJson = sendHttpGet(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() == HttpStatus.SC_OK) {
			return ((JSONArray) httpRespJson.getData());
		} else {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 从MGM获取指定的集群信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @param mgmClusterId
	 *            MGM集群编码
	 * @return MGM集群信息
	 * @throws APIException
	 *             API异常处理类
	 */
	private JSONObject getClusterInfoFromMGM(String siteId, String mgmClusterId) throws APIException {
		String urlPattern = "/{0}/clusters/{1}";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, mgmClusterId);
		RespJson httpRespJson = sendHttpGet(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() == HttpStatus.SC_OK) {
			return ((JSONObject) httpRespJson.getData());
		} else {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 从MGM集群列表中获取指定的集群信息
	 * 
	 * @param mgmClusterInfos
	 *            MGM集群集合
	 * @param mgmClusterId
	 *            MGM集群编码
	 * @return MGM集群信息
	 */
	private JSONObject findClusterInfoFromMGM(JSONArray mgmClusterInfos, String mgmClusterId) {
		if (mgmClusterInfos == null) {
			return null;
		}
		for (int i = 0; i < mgmClusterInfos.size(); i++) {
			JSONObject mgmClusterInfo = mgmClusterInfos.getJSONObject(i);
			if (mgmClusterInfo.getString("id").equals(mgmClusterId)) {
				return mgmClusterInfo;
			}
		}
		return null;
	}

	/**
	 * 向MGM注册集群信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @param paramMap
	 *            请求参数
	 * @return MGM注册集群信息的返回结果
	 * @throws APIException
	 *             API异常处理类
	 */
	private JSONObject saveClusterToMGM(String siteId, Map<String, Object> paramMap) throws APIException {
		JSONObject paramJson = new JSONObject();
		paramJson.put("max_host", (Integer) paramMap.get("maxHostCount"));
		paramJson.put("usage_limit", (Integer) paramMap.get("maxUsage"));
		paramJson.put("ha_network_tag", (String) paramMap.get("haNetworkTag"));

		String urlPattern = "/{0}/clusters";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION);
		RespJson httpRespJson = sendHttpPost(siteId, SysConstants.INTERFACE_TYPE_MGM, url, paramJson.toJSONString());
		if (httpRespJson.getStatus() != HttpStatus.SC_CREATED) {
			throw new APIException(httpRespJson.getMsg());
		}
		return (JSONObject) httpRespJson.getData();
	}

	/**
	 * 更新MGM上指定的集群信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @param mgmClusterId
	 *            MGM集群编码
	 * @param paramMap
	 *            请求参数
	 * @throws APIException
	 *             API异常处理类
	 */
	private void updateClusterFromMGM(String siteId, String mgmClusterId, Map<String, Object> paramMap)
			throws APIException {
		JSONObject paramJson = new JSONObject();
		if (paramMap.containsKey("maxHostCount")) {
			paramJson.put("max_host", (Integer) paramMap.get("maxHostCount"));
		}
		if (paramJson.containsKey("maxUsage")) {
			paramJson.put("usage_limit", (Integer) paramMap.get("maxUsage"));
		}
		if (paramJson.containsKey("haNetworkTag")) {
			paramJson.put("ha_network_tag", (Integer) paramMap.get("haNetworkTag"));
		}

		if (!paramJson.isEmpty()) {
			String urlPattern = "/{0}/clusters/{1}";
			String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, mgmClusterId);
			RespJson httpRespJson = sendHttpPut(siteId, SysConstants.INTERFACE_TYPE_MGM, url, paramJson.toJSONString());
			if (httpRespJson.getStatus() != HttpStatus.SC_OK) {
				throw new APIException(httpRespJson.getMsg());
			}
		}

	}

	/**
	 * 删除MGM上的指定集群信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @param mgmClusterId
	 *            MGM集群编码
	 * @throws APIException
	 *             API异常处理类
	 */
	private void removeClusterFromMGM(String siteId, String mgmClusterId) throws APIException {
		String urlPattern = "/{0}/clusters/{1}";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, mgmClusterId);
		RespJson httpRespJson = sendHttpDelete(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() != HttpStatus.SC_NO_CONTENT) {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 构建集群展示对象
	 * 
	 * @param cluster
	 *            集群对象
	 * @param showDetail
	 *            是否展示详情
	 * @param mgmClusterInfo
	 *            MGM集群对象
	 * @return 集群展示对象
	 */
	private ClusterDto buildShowDto(ClusterEntity cluster, boolean showDetail, JSONObject mgmClusterInfo) {
		ClusterDto clusterDto = new ClusterDto();
		AreaEntity area = cluster.getArea();
		SiteEntity site = area.getSite();
		clusterDto.setSiteId(site.getId());
		clusterDto.setSiteName(site.getName());
		clusterDto.setAreaId(area.getId());
		clusterDto.setAreaName(area.getName());
		clusterDto.setId(cluster.getId());
		clusterDto.setName(cluster.getName());
		clusterDto.setMixed(cluster.getMixed());
		String[] dfSubServNameArr = cluster.getDefinitionSubServNames().split(",");
		List<Map<String, String>> dfSubServNames = new ArrayList<Map<String, String>>(dfSubServNameArr.length);
		for (String name : dfSubServNameArr) {
			Map<String, String> map = new HashMap<String, String>();
			map.put("id", name);
			map.put("name", name);
			dfSubServNames.add(map);
		}
		List<NetworkingEntity> networkings = cluster.getNetworkings();
		List<NetworkingDto> networkingDtos = new ArrayList<NetworkingDto>(networkings.size());
		for (NetworkingEntity networking : networkings) {
			NetworkingDto networkingDto = new NetworkingDto();
			networkingDto.setId(networking.getId());
			networkingDto.setName(networking.getName());
			networkingDtos.add(networkingDto);
		}
		clusterDto.setNetworkings(networkingDtos);
		clusterDto.setDefinitionSubServNames(dfSubServNames);
		clusterDto.setEnabled(cluster.getEnabled());
		clusterDto.setEnabledText(
				dictTypeCache.getTextFromCache(DictTypeConstants.STATUS_ENABLED, String.valueOf(cluster.getEnabled())));
		if (mgmClusterInfo != null) {
			clusterDto.setMaxHostCount(mgmClusterInfo.getIntValue("max_host"));
			clusterDto.setMaxUsage(mgmClusterInfo.getIntValue("usage_limit"));
			clusterDto.setHaNetworkTag(mgmClusterInfo.getString("ha_network_tag"));
		}
		clusterDto.setDescription(cluster.getDescription());
		clusterDto.setCreateDateTime(DateUtils.dateTimeToString(cluster.getCreateDateTime()));
		clusterDto.setCreateLoginUserName(cluster.getCreateUserLoginName());
		return clusterDto;
	}

	/**
	 * 构建集群对象
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return 集群对象
	 */
	@SuppressWarnings("unchecked")
	private ClusterEntity buildCluster(Map<String, Object> paramMap) {
		ClusterEntity cluster = new ClusterEntity();
		cluster.setId(PrimaryKeyUtils.uniqueId());
		AreaEntity area = new AreaEntity();
		area.setId((String) paramMap.get("area"));
		cluster.setArea(area);
		cluster.setName(StringUtils.trim((String) paramMap.get("name")));
		Boolean mixed = (Boolean) paramMap.get("mixed");
		if (mixed == null) {
			mixed = false;
		}
		cluster.setMixed(mixed);
		cluster.setEnabled(true);
		List<String> definitionSubServNames = (List<String>) paramMap.get("definitionSubServs");
		String dfSubServNames = StringUtils.join(definitionSubServNames.toArray(), ",");
		cluster.setDefinitionSubServNames(dfSubServNames);
		List<String> networkingIds = (List<String>) paramMap.get("networkings");
		List<NetworkingEntity> networkings = new ArrayList<NetworkingEntity>(networkingIds.size());
		for (String networkingId : networkingIds) {
			NetworkingEntity networking = new NetworkingEntity();
			networking.setId(networkingId);
			networkings.add(networking);
		}
		cluster.setNetworkings(networkings);
		if (paramMap.containsKey("description")) {
			cluster.setDescription(StringUtils.trim((String) paramMap.get("description")));
		}
		cluster.setCreateDateTime(systemDao.getCurrentDateTime());
		UserEntity user = getUser();
		String username = user.getUsername();
		cluster.setCreateUserLoginName(username);
		return cluster;
	}

	/**
	 * 构建集群对象用于更新
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return 集群对象
	 */
	@SuppressWarnings("unchecked")
	private ClusterEntity buildClusterToUpdate(Map<String, Object> paramMap) {
		String clusterId = (String) paramMap.get("clusterId");
		ClusterEntity cluster = clusterDao.get(clusterId);

		if (paramMap.containsKey("area")) {
			AreaEntity area = new AreaEntity();
			area.setId((String) paramMap.get("area"));
			cluster.setArea(area);
		}

		if (paramMap.containsKey("name")) {
			cluster.setName((String) paramMap.get("name"));
		}

		if (paramMap.containsKey("mixed")) {
			cluster.setMixed((Boolean) paramMap.get("mixed"));
		}

		if (paramMap.containsKey("definitionSubServs")) {
			List<String> definitionSubServNames = (List<String>) paramMap.get("definitionSubServs");
			String dfSubServNames = StringUtils.join(definitionSubServNames.toArray(), ",");
			cluster.setDefinitionSubServNames(dfSubServNames);
		}

		if (paramMap.containsKey("networkings")) {
			List<String> networkingIds = (List<String>) paramMap.get("networkings");
			List<NetworkingEntity> networkings = new ArrayList<NetworkingEntity>(networkingIds.size());
			for (String networkingId : networkingIds) {
				NetworkingEntity networking = new NetworkingEntity();
				networking.setId(networkingId);
				networkings.add(networking);
			}
			cluster.setNetworkings(networkings);
		}

		if (paramMap.containsKey("description")) {
			cluster.setDescription(StringUtils.trim((String) paramMap.get("description")));
		}
		return cluster;
	}
}
